<?php

namespace WeForge\Runtime\Handlers;

use GuzzleHttp\Client;
use Illuminate\Support\Str;
use Swoole\Coroutine\System;
use Throwable;
use WeForge\Runtime\Context;
use WeForge\Runtime\Response;

class ArtisanHandler
{
    /**
     * @param  \Swoole\Http\Request $request
     *
     * @return Response
     */
    public function handle($request)
    {
        $content = json_decode($request->getContent());
        $payload = json_decode($content->payload, true);

        $start = microtime(true);

        $result = System::exec(implode(' ', array_filter([
            str_replace('php artisan', '/home/layer/bin/php /code/artisan', $payload['cli']),
            $this->buildContext(),
            '--no-interaction 2>&1',
        ])));

        [$log, $output] = $this->outputHandler($result);

        $this->ping($payload['callback'] ?? null, $response = [
            'fc_request_id' => $request->header['x-fc-request-id'] ?? null,
            'status_code' => $result['code'],
            'started_at' => $start,
            'finished_at' => microtime(true),
            'log' => base64_encode(implode("\n", $log)),
            'output' => base64_encode(implode("\n", $output)),
        ]);

        return new Response($response);
    }

    protected function buildContext()
    {
        if (!$context = Context::all()) {
            return;
        }

        return '--weforge-context='.base64_encode(json_encode($context));
    }

    /**
     * Handle process output.
     *
     * @return array
     */
    protected function outputHandler(array $result)
    {
        $log = [];
        $output = [];

        foreach (explode("\n", $result['output']) as $line) {
            if (Str::containsAll($line, ['{"message":', '"level":'])) {
                $log[] = $line;

                fwrite(STDERR, $line.PHP_EOL);
            } else {
                $output[] = $line;
            }
        }

        return [$log, $output];
    }

    /**
     * @param  string $url
     * @param  array $json
     *
     * @return void
     */
    protected function ping($url, $json)
    {
        if (! $url) {
            return;
        }

        try {
            (new Client)->post($url, compact('json'));
        } catch (Throwable $e) {
            //
        }
    }
}
